# 数据加载
from sklearn import datasets
import matplotlib.pyplot as plt
import numpy as np

# 获取数据集并进行探索
iris = datasets.load_iris( )
irisFeatures = iris[ "data" ]
irisFeaturesName = iris[ "feature_names" ]
irisLabels = iris[ "target"]

def norm2(x):   
    #求2范数的平方值
    return np.sum(x*x)


class KMeans(object):
    def __init__(self,k:int,n:int):
    #k:聚类的数目，n:数据维度
        self.K =k
        self.N =n
        self.u=np.zeros((k,n))
        self.C=[[]for i in range(k)]
        #u[i]:第i个聚类中心，C[i]：第i个类别所包含的点
        self.J_history = []  # 保存每轮迭代后的目标函数值

    def fit(self,data:np.ndarray):
    #data:每一行是一个样本
        self.select_u0(data)#聚类中心初始化
        J=0
        oldJ=100
        iteration = 0  # 记录迭代轮数
        while abs(J-oldJ)>0.001:
            oldJ=J
            J=0
            self.C=[[]for i in range(self.K)]
            for x in data:
                nor=[norm2(self.u[i]-x)\
                    for i in range(self.K)]
                J+=np.min(nor)
                self.C[np.argmin(nor)].append(x)
            self.u=[np.mean(np.array(self.C[i]),axis=0)\
                for i in range(self.K)]
            self.J_history.append(J)  # 保存目标函数值
            iteration += 1
            print(f"Iteration: {iteration}, Objective Function: {J}")

    def select_u0(self,data:np.ndarray):
        for j in range(self.N):
        #得到该列数据的最小值，最大值
            minJ=np.min(data[:,j])
            maxJ=np.max(data[:,j])
            rangeJ =float(maxJ -minJ)
            #聚类中心的第j维数据值随机为位于(最小值，最大值)内
            self.u[:,j]=minJ+rangeJ *np.random.rand(self.K)

model =KMeans(2,4)
#k=3,n=4
model.fit(irisFeatures)

x=np.array(model.C[0])
plt.scatter(x[:,0],x[:,1],c="red",marker='o',label='cluster1')
x=np.array(model.C[1])
plt.scatter(x[:,0],x[:,1],c="green",marker='*',label='cluster2')
# x=np.array(model.C[2])
# plt.scatter(x[:,0],x[:,1],c="blue",marker='+',label='cluster3')
# x=np.array(model.C[3])
# plt.scatter(x[:,0],x[:,1],c="orange",marker='^',label='cluster4')
# x=np.array(model.C[4])
# plt.scatter(x[:,0],x[:,1],c="purple",marker='s',label='cluster5')
u=np.array(model.u)
plt.scatter(u[:,0],u[:,1],c="black",marker='X',label='center')
plt.xlabel('petal length')
plt.ylabel('petal width')
plt.legend(loc=2)
plt.show()

# 绘制目标函数值与迭代轮数的关系图
plt.plot(range(1, len(model.J_history) + 1), model.J_history)
plt.xlabel('Iteration')
plt.ylabel('Objective Function')
plt.title('Convergence of KMeans Algorithm')
plt.show()

